package redis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * RedisCuckooFilter 是一个基于 Redis 的布谷鸟过滤器实现。
 * 它利用 Redis 的布谷鸟过滤器功能（通常通过 RedisBloom 模块提供的 CF.* 命令）来实现分布式环境下的布谷鸟过滤器。
 * 布谷鸟过滤器是一种高效的近似数据结构，用于快速判断一个元素是否存在于集合中。
 */
public class RedisCuckooFilter {
    private JedisPool jedisPool; // Redis 连接池

    /**
     * 构造函数，初始化 RedisCuckooFilter。
     *
     * @param host Redis 服务器的主机地址
     * @param port Redis 服务器的端口号
     */
    public RedisCuckooFilter(String host, int port) {
        // 创建一个 JedisPool 实例，用于管理 Redis 连接
        jedisPool = new JedisPool(host, port);
    }

    /**
     * 创建一个新的布谷鸟过滤器。
     *
     * @param key      布谷鸟过滤器的键名
     * @param capacity 布谷鸟过滤器的初始容量
     */
    public void createFilter(String key, int capacity) {
        try (Jedis jedis = jedisPool.getResource()) {
            // 检查 Redis 中是否已经存在指定键的布谷鸟过滤器
            if (!jedis.exists(key)) {
                // 使用 Lua 脚本调用 Redis 的 CF.RESERVE 命令来创建过滤器
                String script = "redis.call('CF.RESERVE', KEYS[1], ARGV[1])";
                // 执行 Lua 脚本
                jedis.eval(script, 1, key, String.valueOf(capacity));
            }
        } catch (Exception e) {
            // 打印异常信息
            e.printStackTrace();
        }
    }

    /**
     * 向布谷鸟过滤器中添加一个元素。
     *
     * @param key  布谷鸟过滤器的键名
     * @param item 要添加的元素
     * @return 如果添加成功返回 true，否则返回 false
     */
    public boolean addItem(String key, String item) {
        try (Jedis jedis = jedisPool.getResource()) {
            // 使用 Lua 脚本调用 Redis 的 CF.ADD 命令来添加元素
            String script = "redis.call('CF.ADD', KEYS[1], ARGV[1])";
            // 执行 Lua 脚本
            Object result = jedis.eval(script, 1, key, item);
            // 检查返回结果，判断是否添加成功
            return result != null && ((Long) result) == 1;
        } catch (Exception e) {
            // 打印异常信息
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 检查一个元素是否存在于布谷鸟过滤器中。
     *
     * @param key  布谷鸟过滤器的键名
     * @param item 要检查的元素
     * @return 如果元素存在返回 true，否则返回 false
     */
    public boolean existsItem(String key, String item) {
        try (Jedis jedis = jedisPool.getResource()) {
            // 使用 Lua 脚本调用 Redis 的 CF.EXISTS 命令来检查元素是否存在
            String script = "redis.call('CF.EXISTS', KEYS[1], ARGV[1])";
            // 执行 Lua 脚本
            Object result = jedis.eval(script, 1, key, item);
            // 检查返回结果，判断元素是否存在
            return result != null && ((Long) result) == 1;
        } catch (Exception e) {
            // 打印异常信息
            e.printStackTrace();
            return false;
        }
    }
}